// 柯里化
// 是把接受多个参数的函数变换成接受一个单一参数（最初函数的第一个参数）的函数，
// 并且返回 接受余下的参数而且返回结果 的新函数


function curry(fn) {
  // 获取原函数需要的参数个数
  const arity = fn.length;

  // 定义柯里化的递归函数
  function curried(...args) {
    // 如果当前参数数量 >= 原函数需要的参数数量
    if (args.length >= arity) {
      // 直接执行原函数并返回结果
      return fn.apply(this, args);  // apply 方法可以指定函数执行时的 this 值，这里将其设置为当前的 this 值，同时将参数数组 args 传递给原函数
    } else {
      // 返回一个新的匿名函数，该函数接收新的参数 ...newArgs，并使用 args.concat(newArgs) 将已有参数和新参数合并，然后递归调用 curried 函数继续收集参数
      return function (...newArgs) {
        // 合并已有参数和新参数，递归调用
        return curried.apply(this, args.concat(newArgs));
      }
    }
  }

  return curried;
}

// 使用示例
function add(a, b, c) {
  return a + b + c;
}

const curriedAdd = curry(add);

console.log(curriedAdd(1)(2)(3));   // 6
console.log(curriedAdd(1, 2)(3));   // 6
console.log(curriedAdd(1)(2, 3));   // 6
console.log(curriedAdd(1, 2, 3));   // 6
// console.log(curriedAdd(1));